package com.wjx.config.aop;

import com.wjx.common.datasource.DS;
import com.wjx.common.datasource.DataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Description: 创建一个切面来切换数据源
 * @Auther: wjx
 * @Date: 2019/3/15 10:25
 */
@Aspect
@Component
@Slf4j
public class DynamicDataSourceAspect {


    @Pointcut("@annotation(com.wjx.common.datasource.DS)")
    public void pointCut(){};

    @Before("pointCut()")
    public void beforeSwitchDS(JoinPoint joinPoint) {

        /**
         * 注意:采用倒推思想，前提是对反射原理一定要了解
         *
         * 1-->6.既然想切换数据源，至少我们要知道切换的数据源value是多少
         * 2-->5.获取数据源的value，前提要获取当前的注解DS
         * 3-->4.DS是通过method方法获取的
         * 4-->3.所以先要获取当前的操作method aClass.method("方法名","参数");
         * 5-->2.获取当前的类
         * 6-->1.获取方法名是是什么，当前参数是什么
         *
         * 思路理清楚，开始写代码
         */


        /**
         * 1.获取当前的方法名、获取当前的参数列表
         *
         * 分析思路：
         * joinPoint.getSignature 获取的是 Signature 对象
         * MemberSignature 继承了 Signature对象
         * CodeSignature 继承了 MemberSignature对象
         * MethodSignature 继承了 CodeSignature
         * 将Signature 向下转换为 MethodSignature 去获取 CodeSignature 的属性 getParameterTypes
         * ok，开始
         */
        String methodName = joinPoint.getSignature().getName();

        Class[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        //2.获取当前的类
        Class<?> aClass = joinPoint.getTarget().getClass();
        //设置默认数据源
        String dataBaseName = DataSourceContextHolder.MASTER_DATABASE;
        try {
            //3.通过aClass.method("方法名","参数");获取当前方法
            Method method = aClass.getMethod(methodName, parameterTypes);
            //判断当前类是不是存在DS注解
            if (method.isAnnotationPresent(DS.class)) {
                //4.存在，获取当前的注解
                DS ds = method.getAnnotation(DS.class);
                //5.获取value值
                dataBaseName = ds.value();

            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //6.切换数据源
        log.info("==>  AOP切面before:切换数据源,{}", dataBaseName);
        DataSourceContextHolder.setDB(dataBaseName);
    }

    @After("pointCut()")
    public void afterSwitchDS(){
        log.info("==>  AOP切面after:清除数据源");
        DataSourceContextHolder.clearDB();
    }
}
